\section{std::thread}
\subsection{多线程}
\href{https://www.cnblogs.com/wangguchangqing/p/6134635.html}{线程管理}一文解释了并发编程常见的一些问题和现象。线程内存空间如\figref{fig:thread_memory}
\begin{figure}
    \centering
    \includegraphics[width=0.5\textwidth]{thread_memory}
    \caption{但线程和多线程内存示意图}
    \label{fig:thread_memory}
\end{figure}
下面函数实现对整数的输出：
\begin{longlisting}
\cppfile{code/thread/thread/thread_obj/output_integer.cxx}
\caption{}
\label{}
\end{longlisting}

调用主函数开启8线程执行（实验计算机为4核心8线程），
\begin{longlisting}
\cppfile{code/thread/thread/main.cpp}
\caption{}
\label{}
\end{longlisting}

输出结果如下(每次运行结果可能并不一样)：
\begin{bash}
    0 2 3 1 4 5 7
\end{bash}
输出结果并不是按照顺序输出，这是因为创建的0-7这8个对象竞争CPU的状态不一样，那一个线程获取到了CPU的时间片，这个线程将被优先执行。
使用如下方式创建线程：
\begin{cpp}
#include<pthread.h>
pthread_create(thread,attr,start_routine,arg)
\end{cpp}
这里的pthread\_create创建一个新的线程，并且让它可以执行。
\begin{table}
    \centering
    \begin{tabular}{p{0.2\textwidth}p{0.8\textwidth}}
        \toprule
        参数           & 描述                                                                                         \\
        \midrule
        thread         & 指向线程标识符的指针                                                                         \\
        attr           & 一个不透明的属性对象，可以被用来设置线程属性。可以指定线程属性对象也可以使用默认值NULL。     \\
        start\_routine & 线程运行函数其实地址，一旦线程被创建就会执行                                                 \\
        arg            & 运行函数的参数。它必须通过把引用作为指针强制转换为void类型传递。如果没有传递参数，则使用NULL \\
        \bottomrule
    \end{tabular}
\end{table}
创建线程成功时函数返回0,若返回值不为0，则说明创建线程失败。
\subsection{终止线程}
下面的程序用来终止一个POSIX线程：
\begin{cpp}
#include<pthread.h>
pthread_exit(status)
\end{cpp}
这里的，pthread\_exit用于显式的退出一个线程。通常情况下，thread\_exit()函数是在线程完成后无需继续存在时被调用。如果这里的main()是它所在线程之前结束，通过pthread\_exit()退出，那么其它的线程将继续执行。否则，它们将在main()结束后自动被终止。
% \begin{longlisting}
% \cppfile{thread/ex1/main.cpp}
% \caption{}
% \label{}
% \end{longlisting}

\subsection{thread类}
this\_thread下函数如\tabref{tab:this_thread}
\begin{table}
    \centering
    \caption{std::this\_thread空间下函数}
    \begin{tabular}{p{.2\textwidth}p{.8\textwidth}}
        \toprule
        函数名称&函数说明\\
        \midrule
        \href{https://www.apiref.com/cpp-zh/cpp/thread/yield.html}{yield(C++)}& 建议实现重新调度各线程\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/get_id.html}{get\_id} & 返回当前线程的线程id\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/sleep_for.html}{sleep\_for}& 让当前线程等待指定的时间\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/sleep_until.html}{sleep\_until}&让当前线程的等待直到特定时间点后运行\\
        \bottomrule
    \end{tabular}
    \label{tab:this_thread}
\end{table}

线程对象的成员变量：
\begin{itemize}
    \item id:线程id
    \item native\_hand\_type:本地handle类型。
\end{itemize}

成员函数如下\tabref{tab:thread}
\begin{table}
    \centering
    \caption{线程库成员函数和变量}
    \label{tab:thread}
    \begin{tabular}{ll}
        \toprule
        函数名称              & 说明             \\
        \midrule
        构造函数              & 构造线程         \\
        析构函数              & 销毁线程         \\
        operator=             & 赋值线程         \\
        get\_id               & 获取线程id       \\
        joinable              & 检查是否可以加入 \\
        join                  & 加入线程         \\
        detach                & 分离线程         \\
        swap                  & 交换线程         \\
        native\_handle        & 给定本地handdle  \\
        hardware\_concurrency & 检测硬件并发     \\
        \bottomrule
    \end{tabular}
\end{table}
\begin{itemize}
    \item 默认构造的线程对象不表达为执行的线程，所以是unjoinable。
    \item 被移开的线程将不表达为执行的线程，所以是unjoinable。
\end{itemize}
在std::thread的析构函数中，std::terminate会被调用如果：
\begin{itemize}
    \item 线程没有被Joined（用t.join()）
    \item 线程也没有被detached（用t.detach()）
\end{itemize}
因此，你应该在执行流程到析构函数前总是要么join，要么detach一个线程。
\begin{longlisting}
\cppfile{sample/thread/thread_detach_demo.cc}
\caption{thread:detach}
\label{code:thread_detach}
\end{longlisting}

C++中的thread对象通常来说表达了线程执行，这是一个操作系统或者平台的概念。
当thread::join()函数被调用后，调用它的线程会被阻塞，直到线程的执行被完成。基本上，这是一种可以用来知道一个线程已结束的机制。当thread::join()返回时，操作系统的执行的线程已经完成，C++线程对象可以被销毁。当thread::detach()函数被调用后，执行的线程从线程对象中被分离，已不再被一个线程对象所表达--这是两个独立的事情。C++线程对象可以被销毁，同时操作系统执行的线程可以继续。如果程序想要知道执行的线程何时结束，就需要一些其它的机制。join()函数在那个thread对象上不能再被调用，因为它已经不再和一个执行的线程相关联。去销毁一个仍然可以“joinable”的C++线程对象会被认为是一种错误。为了销毁一个C++线程对象，要么join()函数需要被调用（并结束），要么detach()函数被调用。如果一个C++线程对象当销毁时仍然可以被join，异常会被抛出。C++线程对象不被表达为执行的线程的其它的情况（也就是unjoinable）：
\begin{longlisting}
\cppfile{code/thread/ex11/main.cpp}
\caption{}
\label{}
\end{longlisting}

\begin{remark}
    多线程代码需要 \bashinline{clang++ yourcode.cc -o main -lpthread} 。
\end{remark}

\begin{itemize}
\item join()：
% \begin{longlisting}
% \cppfile{sample/thread/thread_join_demo.cc}
% \caption{thread:join}
% \label{code:join}
% \end{longlisting}

\item joinable():如果一个线程对象表示线程的执行表明对象是可以joinable。在下面的情况下，线程不可joinable：
\begin{itemize}
    \item 如果它被默认构造
    \item 如果它被从(构造另一个线程对象或者赋值给它)移除
    \item 如果它的成员函数join或者detach被调用
\end{itemize}
\item native\_handle：如果库实现支持这个函数仅仅在类中表示，如果表示，它返回一个值用于线程的implement-specific信息。
thread::operator=:如果对象当前不能joinable,它通过ths获取线程执行表示。如果是jointable，terminate()被调用。在调用后，rhs不再表示任何线程执行(就好象默认的构造函数)，线程对象不能复制。
\item swap()线程对象的状态和\*this交换。
\end{itemize}
\section{std::mutex}
互斥算法避免多个线程同时访问共享资源。这会避免数据竞争，并提供线程间的同步支持。定义于头文件 <mutex>，公共成员函数：
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/mutex/lock.html}{lock}：锁定互斥量，若互斥量不可用则阻塞。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/mutex/try_lock.html}{try\_lock}：尝试锁定互斥量，若互斥量不可用则返回。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/mutex/unlock.html}{unlock}：解锁互斥量。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/mutex/native_handle.html}{native\_handle}：返回底层实现定义的原生句柄
\end{itemize}
\begin{longlisting}
\cppfile{sample/thread/thread_mutex_lock_demo.cc}
\caption{thread\_mutex\_lock}
\label{code:thread_mutex_lock1}
\end{longlisting}

\begin{itemize}
\item \href{https://www.apiref.com/cpp-zh/cpp/thread/mutex.html}{mutex}：基本的互斥类
\begin{longlisting}
\cppfile{sample/thread/thread_mutex_lock_demo.cc}
\caption{thread\_mutex\_lock示例2}
\label{code:thread_mutex_lock2}
\end{longlisting}

    \item    \href{https://www.apiref.com/cpp-zh/cpp/thread/timed_mutex.html}{timed\_mutex}：timed\_mutex 类是能用于保护数据免受多个线程同时访问的同步原语。以类似 mutex 的行为， timed\_mutex 提供排他性非递归所有权语义。另外， timed\_mutex 提供通过 try\_lock\_for() 和 try\_lock\_until() 方法试图带时限地要求 timed\_mutex 所有权的能力。timed\_mutex 类满足定时互斥体 (TimedMutex) 与标准布局类型 (StandardLayoutType) 的所有要求。
\begin{longlisting}
\cppfile{sample/thread/thread_time_mutex_lock_demo.cc}
            \caption{thread\_time\_mutex\_lock}
\label{code:thread_time_mutex_lock}
\end{longlisting}
std::timed\_mutex::try\_lock\_for：尝试锁互斥。阻塞直到经过指定的 timeout\_duration 或得到锁，取决于何者先到来。成功获得锁时返回 true ， 否则返回 false 。若 timeout\_duration 小于或等于 timeout\_duration.zero() ，则函数表现同 try\_lock() 。由于调度或资源争议延迟，此函数可能阻塞长于 timeout\_duration 。标准推荐用 steady\_clock 度量时长。若实现用 system\_clock 代替，则等待时间亦可能对时钟调整敏感。同 try\_lock() ，允许此函数虚假地失败并返回 false ，即使在 timeout\_duration 中某点互斥不为任何线程所锁定。若此操作返回 true ，则同一互斥上先前的 unlock() 调用同步于（定义于 std::memory\_order ）它。若已占有 mutex 的线程调用 try\_lock\_for ，则行为未定义。
\begin{longlisting}
\cppfile{sample/thread/thread_time_mutex_try_lock_for_demo.cc}
\caption{thread\_time\_mutex\_try\_lock\_for}
\label{code:thread_time_mutex_try_lock_for}
\end{longlisting}

代码在每个线程里面设置了三次循环，每次循环等待100ms之后尝试获取锁，下面是可能的一个输出。表示第一个线程被调度到，然后在循环里面等待100ms尝试锁定数据，尝试了三次均没有获得锁执行完成后线程推出。然后第二个线程进来尝试了三次依然没有获取到锁，然后退出了。这时调度到0号线程，她成功锁定数据，然后进入代码等待100ms后进入下次循环，直到线程执行结束。同样三号进程也获得了锁，成功执行了代码。
执行输出如下：
        \begin{bash}
第 0 次尝试获取 [1]的锁，但没有获取到锁
第 1 次尝试获取 [1]的锁，但没有获取到锁
第 2 次尝试获取 [1]的锁，但没有获取到锁

第 0 次尝试获取 [2]的锁，但没有获取到锁
第 1 次尝试获取 [2]的锁，但没有获取到锁
第 2 次尝试获取 [2]的锁，但没有获取到锁

第 0 次尝试获取锁，成功获得锁，线程将等待100ms 
[0]释放互斥锁
第 1 次尝试获取锁，成功获得锁，线程将等待100ms 
[0]释放互斥锁
第 2 次尝试获取锁，成功获得锁，线程将等待100ms 
[0]释放互斥锁

第 0 次尝试获取锁，成功获得锁，线程将等待100ms 
[3]释放互斥锁
第 1 次尝试获取锁，成功获得锁，线程将等待100ms 
[3]释放互斥锁
第 2 次尝试获取锁，成功获得锁，线程将等待100ms 
[3]释放互斥锁
\end{bash}
std::timed\_mutex::try\_lock\_until：尝试所互斥。阻塞直至抵达指定的 timeout\_time 或得到锁，取决于何者先到来。成功获得锁时返回 true ，否则返回 false 。若已经过 timeout\_time ，则此函数表现同 try\_lock() 。使用倾向于 timeout\_time 的时钟，这表示时钟调节有影响。从而阻塞的最大时长可能小于但不会大于在调用时的 timeout\_time - Clock::now() ，依赖于调整的方向。由于调度或资源争议延迟，函数亦可能阻塞长于抵达 timeout\_time 之后。同 try\_lock() ，允许此函数虚假地失败并返回 false ，即使在 timeout\_time 前的某点任何线程都不锁定互斥。若此操作返回 true ，则同一互斥上先前的 unlock() 调用同步于（定义于 std::memory\_order ）它。若已占有 mutex 的线程调用 try\_lock\_until ，则行为未定义。
\begin{longlisting}
\cppfile{sample/thread/thread_time_mutex_try_lock_until_demo.cc}
\caption{thread\_time\_mutex\_try\_lock\_until}
\label{code:thread_time_mutex_try_lock_until}
\end{longlisting}
    \item    \href{https://www.apiref.com/cpp-zh/cpp/thread/recursive_mutex.html}{recursive\_mutex}：recursive\_mutex 类是同步原语，能用于保护共享数据免受从个多线程同时访问。recursive\_mutex 提供排他性递归所有权语义：
        \begin{itemize}
            \item 调用方线程在从它成功调用 lock 或 try\_lock 开始的时期里占有 recursive\_mutex 。此时期间，线程可以进行对 lock 或 try\_lock 的附加调用。所有权的时期在线程调用 unlock 匹配次数时结束。
            \item 线程占有 recursive\_mutex 时，若其他所有线程试图要求 recursive\_mutex 的所有权，则它们将阻塞（对于调用 lock ）或收到 false 返回值（对于调用 try\_lock ）。
            \item 可锁定 recursive\_mutex 次数的最大值是未指定的，但抵达该数后，对 lock 的调用将抛出 std::system\_error 而对 try\_lock 的调用将返回 false 。
        \end{itemize}
                若 recursive\_mutex 在仍为某线程占有时被销毁，则程序行为未定义。 recursive\_mutex 类满足互斥体 (Mutex) 和标准布局类型 (StandardLayoutType) 的所有要求。
recursive\_mutex 的使用场景之一是保护类中的共享状态，而类的成员函数可能相互调用：
        \begin{longlisting}
\cppfile{sample/thread/thread_recursive_mutex_demo.cc}
\caption{thread\_recursive\_mutex}
\label{thread_recursive_mutex}
\end{longlisting}

    \item    \href{https://www.apiref.com/cpp-zh/cpp/thread/recursive_timed_mutex.html}{recursive\_time\_mutex}：提供能被同一线程递归锁定的互斥设施，并设置锁定事件。常见成员函数有:
        \begin{itemize}
            \item lock：锁定互斥量。
            \item try\_lock：尝试锁定互斥量，若互斥量不可用则返回。
            \item try\_lock\_for：等待指定的事件锁定互斥量，无法获取则返回。
            \item try\_lock\_until：尝试等待指定的时间后锁定互斥量。
            \item unlock：解锁互斥量。
        \end{itemize}
    \item    \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_mutex.html}{shared\_mutex(C++17)}：shared\_mutex 类是一个同步原语，可用于保护共享数据不被多个线程同时访问。与便于独占访问的其他互斥类型不同，shared\_mutex 拥有二个访问级别：
        \begin{itemize}
            \item 共享 - 多个线程能共享同一互斥的所有权。
            \item 独占性 - 仅一个线程能占有互斥。
        \end{itemize}
若一个线程已获取独占性锁（通过 lock 、 try\_lock ），则无其他线程能获取该锁（包括共享的）。仅当任何线程均未获取独占性锁时，共享锁能被多个线程获取（通过 lock\_shared 、 try\_lock\_shared ）。在一个线程内，同一时刻只能获取一个锁（共享或独占性）。共享互斥体在能由任何数量的线程同时读共享数据，但一个线程只能在无其他线程同时读写时写同一数据时特别有用。排他性锁定：
        \begin{itemize}
            \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_mutex/lock.html}{lock}：锁定互斥量，若互斥不可用则阻塞。
            \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_mutex/try_lock.html}{try\_lock}：尝试锁定互斥量，若互斥不可用则返回。
            \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_mutex/unlock.html}{unlock}：解锁互斥量
        \end{itemize}
共享锁定：
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_mutex/lock_shared.html}{lock\_shared}：为共享所有权锁，若互斥量不可用则阻塞。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_mutex/try_lock_shared.html}{try\_lock\_shared}：尝试为共享所有权锁定互斥量，若互斥量不可用则返回。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_mutex/unlock_shared.html}{unlock\_shared}：解锁互斥量。
\end{itemize}

shared\_mutex 类满足共享互斥体 (SharedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。
\begin{longlisting}
\cppfile{sample/thread/thread_shared_mutex_demo.cc}
\caption{thread\_shared\_mutex}
\label{code:thread_shared_mutex}
\end{longlisting}

    \item    \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex.html}{shared\_timed\_mutex(C++14)}：shared\_timed\_mutex 类是能用于保护数据免受多个线程同时访问的同步原语。与其他促进排他性访问的互斥类型相反，拥有二个层次的访问：
        \begin{itemize}
            \item 共享 - 多个线程能共享同一互斥的所有权。
            \item 排他性 - 仅一个线程能占有互斥。
        \end{itemize}
        共享互斥通常用于多个读线程能同时访问同一资源而不导致数据竞争，但只有一个写线程能访问的情形。以类似 \href{https://www.apiref.com/cpp-zh/cpp/thread/timed_mutex.html}{timed\_mutex} 的行为， shared\_timed\_mutex 提供通过 \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_for.html}{try\_lock\_for()} 、 \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_until.html}{try\_lock\_until()} 、 \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_shared_for.html}{try\_lock\_shared\_for()} 、 \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_shared_until.html}{try\_lock\_shared\_until()} 方法，试图带时限地要求 shared\_timed\_mutex 所有权的能力。

排他性锁定
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/lock.html}{lock}：锁定互斥，若互斥不可用则阻塞(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock.html}{try\_lock}：尝试锁定互斥，若互斥不可用则返回(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_for.html}{try\_lock\_for}:尝试锁定互斥，若互斥在指定的时限时期中不可用则返回(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_until.html}{try\_lock\_until}：尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/unlock.html}{unlock}：解锁互斥(公共成员函数)
\end{itemize}
共享锁定
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/lock_shared.html}{lock\_shared}：为共享所有权锁定互斥，若互斥不可用则阻塞(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_shared.html}{try\_lock\_shared}：尝试为共享所有权锁定互斥，若互斥不可用则返回(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_shared_for.html}{try\_lock\_shared\_for}：尝试为共享所有权锁定互斥，若互斥在指定的时限时期中不可用则返回(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/try_lock_shared_until.html}{try\_lock\_shared\_until}：尝试为共享所有权锁定互斥，若直至抵达指定时间点互斥不可用则返回(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_timed_mutex/unlock_shared.html}{unlock\_shared}：解锁互斥（共享所有权）(公共成员函数)
\end{itemize}

shared\_timed\_mutex 类满足共享定时互斥体 (SharedTimedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。
\begin{longlisting}
\cppfile{sample/thread/thread_shared_timed_mutex_demo.cc}
\caption{thread\_shared\_timed\_mutex}
\label{thread_shared_timed_mutex}
\end{longlisting}

\end{itemize}
std::defer\_lock\_t 、 std::try\_to\_lock\_t 和 std::adopt\_lock\_t 是用于为 std::lock\_guard 、 std::scoped\_lock 、 std::unique\_lock 和 std::shared\_lock 指定锁定策略的空类标签类型。
\begin{table}
    \centering
    \begin{tabular}{cc}
        \toprule
        类型    &效果\\
\midrule
        defer\_lock\_t    &不获得互斥的所有权\\
        try\_to\_lock\_t    &尝试获得互斥的所有权而不阻塞\\
        adopt\_lock\_t    &假设调用方线程已拥有互斥的所有权\\
    \bottomrule
    \end{tabular}
\end{table}
\begin{longlisting}
\cppfile{sample/thread/thread_lock_tag_t_demo.cc}
\caption{thread\_lock\_tag\_t}
\label{code:thread_lock_tag_t}
\end{longlisting}

\begin{table}
    \caption{通用互斥管理}
    \begin{tabular}{p{.4\textwidth}p{.6\textwidth}}
        \toprule
        类名称&函数说明\\
        \midrule
        \href{https://www.apiref.com/cpp-zh/cpp/thread/lock_guard.html}{lock\_guard}(C++11)&实现严格基于作用域的互斥体所有权包装器(类模板)\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/scoped_lock.html}{scoped\_lock}(C++17)&用于多个互斥体的免死锁 RAII 封装器(类模板)\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/unique_lock.html}{unique\_lock}(C++11)&实现可移动的互斥体所有权包装器(类模板)\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_lock.html}{shared\_lock}(C++14)&实现可移动的共享互斥体所有权封装器(类模板)\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/lock_tag_t.html}{defer\_lock\_t}&\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/lock_tag_t.html}{try\_to\_lock\_t}&用于指定锁定策略的标签类型\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/lock_tag_t.html}{adopt\_lock\_t}&\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/lock_tag.html}{defer\_lock}&\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/lock_tag.html}{try\_to\_lock}&用于指定锁定策略的标签常量(常量)\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/lock_tag.html}{adopt\_lock}&\\
        \bottomrule
    \end{tabular}
\end{table}
通用锁定算法如\tabref{tab:common_lock}
\begin{table}
    \centering
    \caption{通用锁定算法}
    \label{tab:common_lock}
    \begin{tabular}{p{.3\textwidth}p{.7\textwidth}}
    \toprule
        方法&说明\\
        \midrule
        \href{https://www.apiref.com/cpp-zh/cpp/thread/try_lock.html}{try\_lock}&试图通过重复调用 try\_lock 获得互斥体的所有权\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/lock.html}{lock}&锁定指定的互斥体，若任何一个不可用则阻塞\\
        \bottomrule
    \end{tabular}
\end{table}
\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/try_lock.html}{std::try\_lock}}
尝试锁定每个给定的可锁定 (Lockable) 对象 lock1 、 lock2 、 ... 、 lockn ，通过以从头开始的顺序调用 try\_lock 。若调用 try\_lock 失败，则不再进一步调用 try\_lock ，并对任何已锁对象调用 unlock ，返回锁定失败对象的 0 底下标。若调用 try\_lock 抛出异常，则在重抛前对任何已锁对象调用 unlock 。
\begin{longlisting}
\cppfile{sample/thread/thread_try_lock_demo.cc}
\caption{thread\_try\_lock}
\label{code:thread_try_lock}
\end{longlisting}

\subsection{std::lock}
锁定给定的可锁定 (Lockable) 对象 lock1 、 lock2 、 ... 、 lockn ，用免死锁算法避免死锁。以对 lock 、 try\_lock 和 unlock 的未指定系列调用锁定对象。若调用 lock 或 unlock 导致异常，则在重抛前对任何已锁的对象调用 unlock 。
\begin{longlisting}
\cppfile{sample/thread/thread_lock_demo.cc}
\caption{thread\_lock}
\label{code:thread_lock}
\end{longlisting}

\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/once_flag.html}{once\_flag}：确保call\_once值调用函数一次。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/call_once.html}{call\_once}：仅调用函数以此，即使从多个线程调用。
\end{itemize}
\subsection{std::call\_once}
准确执行一次可调用 (Callable) 对象 f ，即使同时从多个线程调用。细节为：
\begin{itemize}
    \item 若在调用 call\_once 的时刻， flag 指示已经调用了 f ，则 call\_once 立即返回（称这种对 call\_once 的调用为消极）。
    \item 否则， call\_once 以参数 std::forward<Args>(args)... 调用 std::forward<Callable>(f) （如同用 std::invoke ）。不同于 std::thread 构造函数或 std::async ，不移动或复制参数，因为不需要转移它们到另一执行线程（称这种对 call\_once 的调用为积极）。
        \begin{itemize}
            \item 若该调用抛异常，则传播异常给 call\_once 的调用方，并且不翻转 flag ，以令其他调用将得到尝试（称这种对 call\_once 的调用为异常）。
            \item 若该调用正常返回（称这种对 call\_once 的调用为返回），则翻转 flag ，并保证以同一 flag 对 call\_once 的其他调用为消极。
        \end{itemize}
\end{itemize}
同一 flag 上的所有积极调用组成单独全序，它们由零或多个异常调用后随一个返回调用组成。该顺序中，每个积极调用的结尾同步于下个积极调用。

从返回调用的返回同步于同一 flag 上的所有消极调用：这表示保证所有对 call\_once 的同时调用都观察到积极调用所做的任何副效应，而无需额外同步。
参数：
\begin{itemize}
    \item flag：对象，对于它只有一个函数得到执行
    \item f：要调用的可调用 (Callable) 对象
\end{itemize}
若对 call\_once 的同时调用传递不同的 f ，则调用哪个 f 是未指定的。被选择函数运行于与传递它的 call\_once 的调用相同的线程。

即使在从多个线程调用时，也保证函数局域静态对象的初始化仅出现一次，这可能比使用 std::call\_once 的等价代码更为高效。此函数的 POSIX 类似物是 pthread\_once 。
\begin{longlisting}
\cppfile{sample/thread/thread_call_once_demo.cc}
\caption{thread\_call\_once}
\label{code:thread_call_once}
\end{longlisting}

\section{std::condition\_variable}
condition\_variable 类是同步原语，能用于阻塞一个线程，或同时阻塞多个线程，直至另一线程修改共享变量（条件）并通知 condition\_variable 。有意修改变量的线程必须
\begin{itemize}
    \item 获得 std::mutex （常通过 std::lock\_guard ）
    \item 在保有锁时进行修改
    \item 在 std::condition\_variable 上执行 notify\_one 或 notify\_all （不需要为通知保有锁）
\end{itemize}
    即使共享变量是原子的，也必须在互斥下修改它，以正确地发布修改到等待的线程。任何有意在 std::condition\_variable 上等待的线程必须
\begin{enumerate}
    \item 在与用于保护共享变量者相同的互斥上获得 std::unique\_lock<std::mutex>
    \item 执行下列之一：
        \begin{enumerate}
            \item 检查条件，是否为已更新或提醒它的情况
            \item 执行 wait 、 wait\_for 或 wait\_until ，等待操作自动释放互斥，并悬挂线程的执行。
            \item condition\_variable 被通知时，时限消失或虚假唤醒发生，线程被唤醒，且自动重获得互斥。之后线程应检查条件，若唤醒是虚假的，则继续等待。
        \end{enumerate}
        或者
        \begin{enumerate}
            \item 使用 wait 、 wait\_for 及 wait\_until 的有谓词重载，它们包揽以上三个步骤
std::condition\_variable 只可与 std::unique\_lock<std::mutex> 一同使用；此限制在一些平台上允许最大效率。 std::condition\_variable\_any 提供可与任何基本可锁定 (BasicLockable) 对象，例如 std::shared\_lock 一同使用的条件变量。
        \end{enumerate}
\end{enumerate}
condition\_variable 容许 wait 、 wait\_for 、 wait\_until 、 notify\_one 及 notify\_all 成员函数的同时调用。

类 std::condition\_variable 是标准布局类型 (StandardLayoutType) 。它非可复制构造 (CopyConstructible) 、可移动构造 (MoveConstructible) 、可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable) 。
\begin{remark}
    无赋值构造函数
\end{remark}
成员函数：
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable/notify_one.html}{notify\_one}：通知一个等待的线程
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable/notify_all.html}{notify\_all}：通知所有等待的线程
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable/wait.html}{wait}：阻塞当前线程，直到条件变量被唤醒
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable/wait_for.html}{wait\_for}：阻塞当前线程，直到条件变量被唤醒，或到指定时限时长。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable/wait_until.html}{wait\_until}：阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable/native_handle.html}{native\_hanndle}：返回原生句柄
\end{itemize}
\begin{longlisting}
\cppfile{sample/thread/thread_condition_variable_demo.cc}
\caption{thread\_condition\_vairable}
\label{code:thread_condition_variable}
\end{longlisting}

\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable_any.html}{std::condition\_variable\_any}}
condition\_variable\_any 类是 std::condition\_variable 的泛化。相对于只在 std::unique\_lock<std::mutex> 上工作的 std::condition\_variable ， condition\_variable\_any 能在任何满足基本可锁定 (BasicLockable) 要求的锁上工作。条件变量语义描述见 std::condition\_variable 。类 std::condition\_variable\_any 是标准布局类型 (StandardLayoutType) 。它非可复制构造 (CopyConstructible) 、可移动构造 (MoveConstructible) 、可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable) 。

若锁是 std::unique\_lock ，则 std::condition\_variable 可能提供更好的性能。
\begin{remark}
    无赋值构造函数
\end{remark}
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable_any/notify_one.html}{notify\_one}：通知一个等待的线程(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable_any/notify_all.html}{notify\_all}：通知所有等待的线程(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable_any/wait.html}{wait}：阻塞当前线程，直到条件变量被唤醒(公共成员函数)
    \item  \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable_any/wait_for.html}{wait\_for}：阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable_any/wait_until.html}{wait\_until}：阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点(公共成员函数)

\end{itemize}
\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/notify_all_at_thread_exit.html}{std::notify\_all\_at\_thread\_exit}}
(C++11 起)notify\_all\_at\_thread\_exit 提供机制，通知其他线程给定的线程已完全完成，包括销毁所有 thread\_local 对象。它操作如下：
\begin{itemize}
    \item 将先前获得的锁 lk 的所有权转移到内部存储。
    \item 修改执行环境，以令当前线程退出时，如同以下列方式通知 condition\_variable cond ：
        \begin{cpp}
        lk.unlock();
cond.notify_all();
        \end{cpp}
\end{itemize}
隐含的 lk.unlock 后序于（定义于 std::memory\_order ）关联到当前线程的，所有拥有线程局域存储期的对象析构。等价的效果可以用 std::promise 或 std::packaged\_task 所提供的设施达成。
\begin{remark}
    \begin{itemize}
        \item 若当前线程未锁定 lock.mutex() ，则调用此函数是未定义行为。

        \item 若 lock.mutex() 与所有其他等待在同一条件变量上的线程所用的互斥不相同，则调用此函数是未定义行为。

        \item 保有提供的锁 lk 直至线程退出。一旦调用此函数，则无更多线程可获得相同的锁，以在 cond 上等待。若某线程在此条件变量上等待，则它在虚假唤醒时不应试图释放和重获得锁。
    \end{itemize}
典型使用情况中，此函数是被脱附线程所做的最后行动。
\end{remark}
\begin{itemize}
\item cond：在线程退出时通知的 conditional\_variable
\item lk：关联到 condition\_variable cond 的锁
\end{itemize}
    \begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable.html}{condition\_variable}：提供和\href{https://www.apiref.com/cpp-zh/cpp/thread/unique_lock.html}{std::unique\_lock}关联的条件变量。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/condition_variable_any.html}{condition\_variable\_any}：提供与任何锁类型关联的条件变量。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/notify_all_at_thread_exit.html}{notify\_all\_at\_thread\_exit}：安排到此线程完全结束时对notify\_all的调用
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/cv_status.html}{cv\_status}：列出条件变量上定时等待的可能结果。
\end{itemize}
\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/cv_status.html}{std::cv\_status}}
带作用域枚举 std::cv\_status 描述定时等待是否因时限返回。

std::cv\_status 为 std::condition\_variable 和 std::condition\_variable\_any 的 wait\_for 和 wait\_until 方法所用。
成员常量：
\begin{itemize}
    \item no\_timeout：条件变量因 notify\_all 、 notify\_one 或虚假地被唤醒
    \item timeout：条件变量因时限耗尽被唤醒
\end{itemize}
\section{std::semaphore}
信号量 (semaphore) 是一种轻量的同步原件，用于制约对共享资源的并发访问。在可以使用两者时，信号量能比条件变量更有效率。定义于头文件 <semaphore>。
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/counting_semaphore.html}{counting\_semaphore}（C++20）实现非负资源计数的信号量\\
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/counting_semaphore.html}{binary\_semaphore}(C++20) 仅拥有两个状态的信号量。
\end{itemize}
\section{std::latch}
闩 (latch) 与屏障 (barrier) 是线程协调机制，允许任何数量的线程阻塞直至期待数量的线程到达该屏障。闩不能复用，屏障能重复使用。定义于头文件 <latch>
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/latch.html}{latch}(C++20) 单次使用的线程屏障。
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/barrier.html}{barrier}(C++20)：可复用的线程屏障。
\end{itemize}
\section{std::future库}
标准库提供了一些工具来获取异步任务（即在单独的线程中启动的函数）的返回值，并捕捉其所抛出的异常。这些值在共享状态中传递，其中异步任务可以写入其返回值或存储异常，而且可以由持有该引用该共享态的 std::future 或 std::shared\_future 实例的线程检验、等待或是操作这个状态。
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/promise.html}{promise}(C++11)：存储一个值以进行异步获取(类模板)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/packaged_task.html}{packaged\_task}(C++11)：打包一个函数，存储其返回值以进行异步获取(类模板)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future.html}{future}(C++11)：等待被异步设置的值(类模板)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_future.html}{shared\_future}(C++11)：等待被异步设置的值（可能为其他 future 所引用）(类模板)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/async.html}{async}(C++11)：异步运行一个函数（有可能在新线程中执行），并返回保有其结果的 std::future(函数模板)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/launch.html}{launch}(C++11)：指定 std::async 所用的运行策略(枚举)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future_status.html}{future\_status}(C++11)：指定在 std::future 和 std::shared\_future 上的定时等待的结果(枚举)
\end{itemize}
Future 错误
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future_error.html}{future\_error}(C++11):报告与 future 或 promise 有关的错误(类)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future/future_category.html}{future\_category}(C++11)：鉴别 future 错误类别(函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future_errc.html}{future\_errc}(C++11)：鉴别 future 错误码(枚举)
\end{itemize}
\subsection{std::promise}
\begin{cpp}
template< class R > class promise;//(1)    (C++11 起)
template< class R > class promise<R&>;//(2)    (C++11 起)
template<>          class promise<void>;//(3)    (C++11 起)
\end{cpp}
\begin{itemize}
    \item 空模板
    \item 非 void 特化，用于在线程间交流对象
    \item void 特化，用于交流无状态事件
\end{itemize}
类模板 std::promise 提供对值或异常的存储，之后通过 std::promise 对象所创建的 std::future 对象异步获得结果。注意 \textcolor{red}{std::promise 只应当使用一次}。

每个 promise 与共享状态关联，共享状态含有一些状态信息和可能仍未求值的结果，它求值为值（可能为 void ）或求值为异常。 promise 可以对共享状态做三件事：
\begin{itemize}
    \item 使就绪： promise 存储结果或异常于共享状态。标记共享状态为就绪，并解除阻塞任何等待与该共享状态关联的 future 上的线程。
    \item 释放： promise 放弃其对共享状态的引用。若这是最后一个这种引用，则销毁共享状态。除非这是 std::async 所创建的未就绪的共享状态，否则此操作不阻塞。
    \item  抛弃： promise 存储以 std::future\_errc::broken\_promise 为 error\_code 的 std::future\_error 类型异常，令共享状态为就绪，然后释放它。
\end{itemize}
promise 是 promise-future 交流通道的“推”端：存储值于共享状态的操作同步于（定义于 std::memory\_order ）任何在共享状态上等待的函数（如 std::future::get ）的成功返回。其他情况下对共享状态的同时访问可能冲突：例如， std::shared\_future::get 的多个调用方必须全都是只读，或提供外部同步。

\MemberFunc
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/promise/swap.html}{swap}：交换二个 promise 对象(公共成员函数)
    \item 获取结果：\href{https://www.apiref.com/cpp-zh/cpp/thread/promise/get_future.html}{get\_future}返回与承诺的结果关联的 future(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/promise/set_value.html}{set\_value}：设置结果为指定值(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/promise/set_value_at_thread_exit.html}{set\_value\_at\_thread\_exit}：设置结果为指定值，同时仅在线程退出时分发提醒(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/promise/set_exception.html}{set\_exception}：设置结果为指示异常(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/promise/set_exception_at_thread_exit.html}{set\_exception\_at\_thread\_exit}:设置结果为指示异常，同时仅在线程退出时分发提醒(公共成员函数)
    \item std::swap(std::promise)：特化 std::swap 算法(函数模板)
    \item std::uses\_allocator<std::promise>(C++11)：特化 std::uses\_allocator 类型特征(类模板特化)
\end{itemize}
\begin{longlisting}
\cppfile{sample/thread/future_promise_demo.cc}
\caption{future\_promise使用示例}
\label{code:future_promise}
\end{longlisting}
输出：
\begin{bash}
result=21
this thead = 140498890188352 started!
\end{bash}
\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/packaged_task.html}{std::packaged\_task}}
定义于头文件 <future>
\begin{cpp}
template< class > class packaged_task; // 不定义(1)    (C++11 起)
template< class R, class ...Args >
class packaged_task<R(Args...)>;//(2)    (C++11 起)
\end{cpp}
类模板 std::packaged\_task 包装任何可调用 (Callable) 目标（函数、 lambda 表达式、 bind 表达式或其他函数对象），使得能异步调用它。其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。

正如 std::function ， std::packaged\_task 是多态、具有分配器的容器：可在堆上或以提供的分配器分配存储的可调用对象。

\textbf{成员函数}：
\begin{itemize}
    \item valid：检查任务对象是否拥有合法函数(公共成员函数)
    \item swap：交换二个任务对象(公共成员函数)获取结果
    \item get\_future：返回与承诺的结果关联的 std::future(公共成员函数)
    \item operator()执行函数(公共成员函数)
    \item make\_ready\_at\_thread\_exit：执行函数，并确保结果仅在一旦当前线程退出时就绪(公共成员函数)
    \item reset：重置状态，抛弃任何先前执行的存储结果(公共成员函数)
    \item std::swap(std::packaged\_task)：(C++11) 特化 std::swap 算法(函数模板)
    \item std::uses\_allocator<std::packaged\_task>：(C++11)(C++17 前)特化 std::uses\_allocator 类型特征(类模板特化)
\end{itemize}
\begin{longlisting}
\cppfile{sample/thread/future_packaged_task_demo.cc}
\label{code:future_packaged_task}
\caption{future::packaged\_task使用示例}
\end{longlisting}
输出：
\begin{bash}
task_lambda:    512
task_bind:      2048
task_thread:    1024
\end{bash}

\begin{cpp}
template< class T > class future;//(1)    (C++11 起)
template< class T > class future<T&>;//(2)    (C++11 起)
template<>          class future<void>;//(3)    (C++11 起)
\end{cpp}
类模板 std::future 提供访问异步操作结果的机制：
\begin{itemize}
    \item （通过 std::async 、 std::packaged\_task 或 std::promise 创建的）异步操作能提供一个 std::future 对象给该异步操作的创建者。
    \item 然后，异步操作的创建者能用各种方法查询、等待或从 std::future 提取值。若异步操作仍未提供值，则这些方法可能阻塞。
    \item 异步操作准备好发送结果给创建者时，它能通过修改链接到创建者的 std::future 的共享状态（例如 std::promise::set\_value ）进行。
注意， std::future 所引用的共享状态不与另一异步返回对象共享（与 std::shared\_future 相反）。
\end{itemize}
\begin{longlisting}
\cppfile{sample/thread/future_sample_demo.cc}
\caption{future 示例}
\label{code:future}
\end{longlisting}
输出：
\begin{bash}
main thread id = 139825672930304
current thread id = 139825672914496
async thread id = Waiting...139825664521792
Done!
Results are: 7 8 9
\end{bash}
\begin{longlisting}
\cppfile{sample/thread/future_exception_sample_demo.cc}
\caption{future exception示例}
\label{code:future_exception}
\end{longlisting}
输出：
\begin{bash}
future value = Exception from the thread: Thread Exception
\end{bash}
成员函数
\begin{itemize}
    \item (构造函数)构造 future 对象
    \item (公共成员函数)(析构函数)析构 future 对象(公共成员函数)
    \item operator=移动future对象(公共成员函数)
    \item share从 *this 转移共享状态给 shared\_future 并返回它(公共成员函数)
    \item 获取结果get返回结果(公共成员函数)
\begin{cpp}
T get();//(1)    (仅为泛型 future 模板的成员)(C++11 起)
T& get();//(2)    (仅为 future<T&> 模板特化的成员)(C++11 起)
void get();//(3)    (仅为 future<void> 模板特化的成员)(C++11 起)
\end{cpp}
get 方法等待直至 future 拥有合法结果并（依赖于使用哪个模板）获取它。它等效地调用 wait() 等待结果。泛型模板和二个模板特化各含单个 get 版本。 get 的三个版本仅在返回类型有别。若调用此函数前 valid() 为 false 则行为未定义。释放任何共享状态。调用此方法后 valid() 为 false 。

\Return
        \begin{enumerate}
            \item 存储于共享状态的值 v ，如同 std::move(v) 。
            \item 存储于共享状态的值的引用。
            \item 无。
        \end{enumerate}
异常:
若 future 所引用的共享状态中存储异常（例如，通过调用 std::promise::set\_exception() ），则抛出该异常。
注意
        \begin{remark}
鼓励实现在调用前检测 valid() 为 false 的情况，并抛出以 std::future\_errc::no\_state 为 error\_condition 的 std::future\_error 。
        \end{remark}
\begin{longlisting}
\cppfile{sample/thread/future_get_sample_demo.cc}
\caption{future::get}
\label{code:future_get}
\end{longlisting}

        输出：
        \begin{bash}
[0.000000s] launching thread,id = 139957290992640
[0.000051s] waiting for the future, f.valid() == 1
[1.000349s] future.get() returned with 7. f.valid() = 0
[1.000399s] launching thread
[1.000486s] waiting for the future, f.valid() == 1
async thread,ID = 139957290976832
[2.000918s] caught exception 7, f.valid() == 0
        \end{bash}
\end{itemize}
状态
\begin{itemize}
    \item valid：检查 future 是否拥有共享状态(公共成员函数)
    \item wait：等待结果变得可用(公共成员函数)
        \begin{longlisting}
\cppfile{sample/thread/future_wait_sample_demo.cc}
\caption{future::wait}
\label{code:future}
\end{longlisting}
        输出：
        \begin{bash}
waiting...
thread id = 139895003481664running
thread id = 139894995088960running
1.14652 seconds
f1: 102334155
f2: 433494437
        \end{bash}
    \item wait\_for:等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。(公共成员函数)
\begin{cpp}
template< class Rep, class Period >
std::future_status wait_for( const std::chrono::duration<Rep,Period>& timeout_duration ) const;//(C++11 起)
\end{cpp}
等待结果变得可用，否则，阻塞直至经过指定的 timeout\_duration ，或结果变为可用，两者的先到来者。返回值鉴别结果的状态。

		此函数可能由于调度或资源争议延迟而阻塞长于 timeout\_duration 。推荐标准库用稳定时钟度量时长。\textcolor{red}{若实现用系统时钟代替，则等待时间可能也对时钟调整敏感}。若调用此函数前 valid()== false 则行为未定义。

\Param
        \begin{itemize}
            \item timeout\_duration    -    要阻塞的最大时长
        \end{itemize}
\Return
        \begin{table}
        \begin{tabular}{cc}
            \toprule
            常量    &解释\\
            \midrule
            \href{https://zh.cppreference.com/w/cpp/thread/future_status}{future\_status::deferred}    &共享状态持有的函数正在延迟运行，结果将仅在显式请求时计算\\
            \href{https://zh.cppreference.com/w/cpp/thread/future_status}{future\_status::ready}    &共享状态就绪\\
            \href{https://zh.cppreference.com/w/cpp/thread/future_status}{future\_status::timeout}    &共享状态在经过指定的等待时间内仍未就绪\\
            \bottomrule
        \end{tabular}
        \end{table}
异常：时钟、时间点或时长在执行中可能抛的任何异常（标准库提供的时钟、时间点和时长决不抛出）。

\begin{remark}
鼓励实现在调用前检测 valid == false 的情况并抛出以 future\_errc::no\_state 为 error\_condition 的 future\_error 。
\end{remark}
\begin{longlisting}
\cppfile{sample/thread/future_wait_for_sample_demo.cc}
\caption{future::wait\_for}
\label{code:future_wait_for}
\end{longlisting}
输出：
\begin{bash}
waiting...
timeout
timeout
ready!
result is 8 
\end{bash}

    \item wait\_until：等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。(公共成员函数)
\begin{cpp}
template< class Clock, class Duration >
std::future_status wait_until( const std::chrono::time_point<Clock,Duration>& timeout_time ) const;//(C++11 起)
\end{cpp}
wait\_until 等待结果变为可用。它阻塞直至抵达指定的 timeout\_time ，或结果变为可用，两者的先到来者。返回值指示 wait\_until 为何返回。

若调用此函数前 valid() 为 false ，或 Clock 不符合时钟 (Clock) 要求则行为未定义。若 std::chrono::is\_clock\_v<Clock> 为 false 则程序为非良构。 (C++20 起)

参数
\begin{itemize}
    \item timeout\_time    ：要阻塞到的最大时间点
\end{itemize}
返回值
\begin{table}
    \begin{tabular}{cc}
        \toprule
        常量    &解释\\
        future\_status::deferred    &共享状态持有的函数正在延迟运行，结果将仅在显式请求时计算\\
        future\_status::ready    &共享状态就绪\\
        future\_status::timeout    &共享状态在经过指定的等待时间内仍未就绪\\
    \end{tabular}
\end{table}
异常：时钟、时间点或时长在执行中可能抛的任何异常（标准库提供的时钟、时间点和时长决不抛出）。

\begin{remark}
鼓励实现在调用前检测 valid() == false 的情况并抛出以 future\_errc::no\_state 为错误条件的 std::future\_error 。
\end{remark}
使用倾向 timeout\_time 的时钟，不要求是单调时钟。若不连续地调节时钟，则不对此函数的行为保证，但既存实现将 timeout\_time 从 Clock 转换到 std::chrono::system\_clock ，并委托 POSIX pthread\_cond\_timedwait 以令等待忠实于系统时钟，但非用户提供 Clock 的调节。任何情况下，由于调度或资源争议延迟，函数可能等待长于抵达 timeout\_time 。
\begin{longlisting}
\cppfile{sample/thread/future_until_for_sample_demo.cc}
\caption{future::until\_for}
\label{code:future_until_for}
\end{longlisting}
输出：
\begin{bash}
Waiting for 2 seconds...
f_completes: 9
f_times_out did not complete!
Done!
\end{bash}

\end{itemize}
\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/future.html}{std::future}}
\begin{cpp}
定义于头文件 <future>
template< class T > class future;//(1)    (C++11 起)
template< class T > class future<T&>;//(2)    (C++11 起)
template<>          class future<void>;//(3)    (C++11 起)
\end{cpp}
类模板 std::future 提供访问异步操作结果的机制：
\begin{itemize}
    \item （通过 std::async 、 std::packaged\_task 或 std::promise 创建的）异步操作能提供一个 std::future 对象给该异步操作的创建者。
    \item 然后，异步操作的创建者能用各种方法查询、等待或从 std::future 提取值。若异步操作仍未提供值，则这些方法可能阻塞。
    \item 异步操作准备好发送结果给创建者时，它能通过修改链接到创建者的 std::future 的共享状态（例如 std::promise::set\_value ）进行。
\end{itemize}
\begin{remark}
std::future 所引用的共享状态不与另一异步返回对象共享（与 std::shared\_future 相反）。
\end{remark}
常见成员函数：
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future/share.html}{share}：从 *this 转移共享状态给 shared\_future 并返回它(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future/get.html}{get}：返回结果(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future/valid.html}{valid}：检查 future 是否拥有共享状态(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future/wait.html}{wait}：等待结果变得可用(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future/wait_for.html}{wait\_for}：等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/future/wait_until.html}{wait\_until}：等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。(公共成员函数)
\end{itemize}
\begin{longlisting}
\cppfile{sample/thread/future_demo.cc}
\caption{future对象使用示例}
\label{code:future_future}
\end{longlisting}
输出：
\begin{bash}
Waiting...Done!
Results are: 7 8 9
\end{bash}
\subsection{std::shared\_future}
\begin{cpp}
template< class T > class shared_future;//(1)    (C++11 起)
template< class T > class shared_future<T&>;//(2)    (C++11 起)
template<>          class shared_future<void>;//(3)    (C++11 起)
\end{cpp}
类模板 std::shared\_future 提供访问异步操作结果的机制，类似 std::future ，除了允许多个线程等候同一共享状态。不同于\textcolor{red}{仅可移动}的 std::future （故只有一个实例能指代任何特定的异步结果），std::shared\_future 可复制而且多个 shared\_future 对象能指代同一共享状态。若每个线程通过其自身的 shared\_future 对象副本访问，则从多个线程访问同一共享状态是安全的。常见成员函数：
\begin{itemize}
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_future/get.html}{get}：返回结果
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_future/valid.html}{valid}：检查 future 是否拥有共享状态(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_future/wait.html}{wait}：等待结果变得可用(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_future/wait_for.html}{wait\_for}：等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。(公共成员函数)
    \item \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_future/wait_until.html}{wait\_until}：等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。(公共成员函数)
\end{itemize}
shared\_future 可用于同时向多个线程发信，类似 std::condition\_variable::notify\_all()
\begin{longlisting}
\cppfile{sample/thread/future_shared_future_demo.cc}
\caption{future\_shared使用示例}
\label{code:future_shared}
\end{longlisting}
输出：
\begin{bash}
Thread 1 received the signal 0.004977 ms after start
Thread 2 received the signal 0.043284 ms after start
\end{bash}
\subsection{std::async}
定义于头文件 <future>
\begin{cpp}
template< class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
    async( Function&& f, Args&&... args );//(C++11 起)(C++17 前)
template< class Function, class... Args>
std::future<std::invoke_result_t<std::decay_t<Function>,
                                              std::decay_t<Args>...>>
    async( Function&& f, Args&&... args );//(C++17 起)(C++20 前)
template< class Function, class... Args>
[[nodiscard]]
std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>
    async( Function&& f, Args&&... args );//(C++20 起)(2)    
template< class Function, class... Args >
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
    async( std::launch policy, Function&& f, Args&&... args );//(C++11 起)(C++17 前)
template< class Function, class... Args >
std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>
    async( std::launch policy, Function&& f, Args&&... args );//(C++17 起)(C++20 前)
template< class Function, class... Args >
[[nodiscard]]
std::future<std::invoke_result_t<std::decay_t<Function>,
                                 std::decay_t<Args>...>>
    async( std::launch policy, Function&& f, Args&&... args );//(C++20 起)
\end{cpp}
函数模板 async 异步地运行函数 f （潜在地在可能是线程池一部分的分离线程中），并返回最终将保有该函数调用结果的 std::future 。
\begin{enumerate}
    \item 表现如同以 policy 为 std::launch::async | std::launch::deferred 调用 (2) 。换言之， f 可能执行于另一线程，或者它可能在查询产生的 std::future 的值时同步运行。
    \item 按照特定的执行策略 policy ，以参数 args 调用函数 f ：
若设置 async 标志（即 (policy \& std::launch::async) != 0 ），则 async 在新的执行线程（初始化所有线程局域对象后）执行可调用对象 f ，如同产出 std::thread(std::forward<F>(f), std::forward<Args>(args)...) ，除了若 f 返回值或抛出异常，则于可通过 async 返回给调用方的 std::future 访问的共享状态存储结果。
        \begin{itemize}
            \item 若设置 deferred 标志（即 (policy \& std::launch::deferred) != 0 ），则 async 以同 std::thread 构造函数的方式转换 f 与 args... ，但不产出新的执行线程。而是进行惰性求值：在 async 所返回的 std::future 上首次调用非定时等待函数，将导致在当前线程（不必是最初调用 std::async 的线程）中，以 args... （作为右值传递）的副本调用 f （亦作为右值）的副本。将结果或异常置于关联到该 future 的共享状态，然后才令它就绪。对同一 std::future 的所有后续访问都会立即返回结果。
            \item 若 policy 中设置了 std::launch::async 和 std::launch::deferred 两个标志，则进行异步执行还是惰性求值取决于实现。
            \item 若 policy 中未设置 std::launch::async 或 std::launch::deferred 或任何实现定义策略标志，则行为未定义。
(C++14 起)
        \end{itemize}
\end{enumerate}
任何情况下，对 std::async 的调用同步于（定义于 std::memory\_order ）对 f 的调用，且 f 的完成先序于令共享状态就绪。若选择 async 策略，则关联线程的完成同步于首个等待于共享状态上的函数的成功返回，或最后一个释放共享状态的函数的返回，两者的先到来者。

参数：
\begin{itemize}
    \item f：要调用的可调用 (Callable) 对象
    \item args...：传递给 f 的参数
    \item policy：位掩码值，每个单独位控制允许的执行方法
\end{itemize}
\begin{table}
    \centering
	\caption{执行策略}
    \begin{tabular}{cc}
		\toprule
        位    &解释\\
		\midrule
        \href{https://www.apiref.com/cpp-zh/cpp/thread/launch.html}{std::launch::async}    &启用异步求值\\
        \href{https://www.apiref.com/cpp-zh/cpp/thread/launch.html}{std::launch::deferred}    &启用惰性求值\\
		\bottomrule
    \end{tabular}
\end{table}
\begin{itemize}
\item \textbf{类型要求}：-Function, Args 必须满足\href{https://www.apiref.com/cpp-zh/cpp/named_req/MoveConstructible.html}{可移动构造 (MoveConstructible) }的要求。
\item \textbf{返回值}:指代此次调用 std::async 所创建的共享状态的 \href{https://www.apiref.com/cpp-zh/cpp/thread/future.html}{std::future} 。
\item \textbf{异常}：若运行策略等于 std::launch::async 且实现无法开始新线程（该情况下，若运行策略为 async|deferred 或设置了额外位，则它将回退到 deferred 或实现定义的策略），则抛出以 std::errc::resource\_unavailable\_try\_again 为错误条件的 std::system\_error ，或者若无法分配内部数据结构所用的内存，则为 std::bad\_alloc 。
\end{itemize}
\begin{Notice}
实现可以通过在默认运行策略中启用额外（实现定义的）位，扩展 std::async 第一重载的行为。

实现定义的运行策略的例子是同步策略（在 async 调用内立即执行）和任务策略（类似 async ，但不清理线程局域对象）。

若从 std::async 获得的 std::future 未被移动或绑定到引用，则在完整表达式结尾， std::future 的析构函数将阻塞直至异步计算完成，实质上令如下代码同步：
    \begin{cpp}
        std::async(std::launch::async, []{ f(); }); // 临时量的析构函数等待 f()
std::async(std::launch::async, []{ g(); }); // f() 完成前不开始
    \end{cpp}
\end{Notice}
（注意，以调用 std::async 以外的方式获得的 std::future 的析构函数决不阻塞）
\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/launch.html}{std::launch}}
定义于头文件 <future>
\begin{cpp}
enum class launch : /* unspecified */ {
    async =    /* unspecified */,
    deferred = /* unspecified */,
    /* implementation-defined */
};
\end{cpp}
(C++11 起)
指定 \href{https://www.apiref.com/cpp-zh/cpp/thread/async.html}{std::async} 所指定的任务的的运行策略。 std::launch 是用作位掩码类型 \href{https://www.apiref.com/cpp-zh/cpp/named_req/BitmaskType.html}{(BitmaskType)} 的枚举。标准库定义下列代表单独位的常量：
\begin{table}[!htbp]
	\centering
    \begin{tabular}{cc}
        \toprule
        常量    &解释\\
\midrule
        std::launch::async    &运行新线程，以异步执行任务\\
        std::launch::deferred    &调用方线程上首次请求其结果时执行任务（惰性求值）\\
		\bottomrule
    \end{tabular}
\end{table}
另外，允许实现：
\begin{itemize}
    \item 定义额外的位和位掩码，以指定可应用于运行策略子集的任务交互上的限制，并
    \item 对 \href{https://www.apiref.com/cpp-zh/cpp/thread/async.html}{std::async} 的首个（默认）重载启用这些额外位掩码。
\end{itemize}
\subsection{std::future\_status}
定义于头文件 <future>
\begin{cpp}
enum class future_status {
    ready,
    timeout,
    deferred
};
(C++11 起)
\end{cpp}
指定 \href{https://www.apiref.com/cpp-zh/cpp/thread/future.html}{std::future} 和 \href{https://www.apiref.com/cpp-zh/cpp/thread/shared_future.html}{std::shared\_future} 的 wait\_for 和 wait\_until 函数所返回的 future 状态。
\begin{table}
	\centering
    \begin{tabular}{cc}
        \toprule
        常量    &解释\\
        deferred    &共享状态含有延迟的函数，故将仅在显式请求时计算结果\\
        ready    &共享状态就绪\\
        timeout    &共享状态在经过指定的时限时长前仍未就绪\\
        \bottomrule
    \end{tabular}
\end{table}
\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/future_error.html}{std::future\_error}}
定义于头文件 <future>
\begin{cpp}
class future_error;
(C++11 起)
\end{cpp}
类 std::future\_error 定义异常对象，它为处理异步执行和共享状态（ \href{https://www.apiref.com/cpp-zh/cpp/thread/future.html}{std::future} 、 \href{https://www.apiref.com/cpp-zh/cpp/thread/promise.html}{std::promise} 等）的线程库中的函数在失败时抛出。同 \href{https://www.apiref.com/cpp-zh/cpp/error/system_error.html}{std::system\_error} ，此异常携带与 \href{https://www.apiref.com/cpp-zh/cpp/error/error_code.html}{std::error\_code} 兼容的错误码。
成员函数
\begin{itemize}
    \item (构造函数)：创建 std::future\_error 对象(公共成员函数)
    \item operator=：替换 std::future\_error 对象(公共成员函数)
    \item code：返回错误码(公共成员函数)
    \item what：返回对错误码指定的解释性字符串(公共成员函数)
\end{itemize}
\begin{longlisting}
\cppfile{sample/thread/future_error_demo.cc}
\caption{future\_error使用示例}
\label{code:future_error}
\end{longlisting}

\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/future/future_category.html}{std::future\_category}}
定义于头文件 <future>
\begin{cpp}
const std::error_category& future_category() noexcept;
\end{cpp}
获得对于 future 和 promise 相关错误的静态 error\_category 对象的引用。要求对象覆写虚函数 error\_category::name() ，以返回指向字符串 "future" 的指针。它亦用于鉴别 std::future\_error 类型异常中提供的 error\_code 。

\Return 到静态对象的引用，其运行时类型导出自 std::error\_category 且未指定。
\subsection{\href{https://www.apiref.com/cpp-zh/cpp/thread/future_errc.html}{std::future\_errc}}
定义于头文件 <future>
\begin{cpp}
enum class future_errc {
    broken_promise             = /* implementation-defined */,
    future_already_retrieved   = /* implementation-defined */,
    promise_already_satisfied  = /* implementation-defined */,
    no_state                   = /* implementation-defined */
};
\end{cpp}
有作用域枚举 std::future\_errc 定义 std::future 及相关类于 std::future\_error 异常对象中报告的错误码。只要求四个错误码，尽管实现可以定义额外的错误码。因为提供了 std::is\_error\_code\_enum 的恰当特化，故 std::future\_errc 类型值可隐式转换为 std::error\_code 。所有错误码均相异且非零。    (C++14 起)
成员常量
 \begin{table}
     \centering
     \begin{tabular}{cc}
         \toprule
         常量    &解释\\
         \midrule
         broken\_promise    &异步任务抛弃其共享状态\\
         future\_already\_retrieved    &共享状态的内容已通过 std::future 访问\\
         promise\_already\_satisfied    &试图两次存储值于共享状态\\
         no\_state    &试图访问无关联共享状态的 std::promise 或 std::future\\
         \bottomrule
     \end{tabular}
 \end{table}
非成员函数
\begin{itemize}
    \item make\_error\_code(std::future\_errc)(C++11)：构造一个 future error\_code(函数)
    \item make\_error\_condition(std::future\_errc)(C++11)：构造一个 future error\_condition(函数)
\end{itemize}
帮助类
is\_error\_code\_enum<std::future\_errc>：扩展类型特性 std::is\_error\_code\_enum 以鉴别 future 错误码(类模板)
\begin{remark}
C++11 中， broken\_promise 曾被指定等于零，不在意 std::error\_code/std::error\_condition 用零表示“无错误”。这在 C++14 中得到修正
\end{remark}

